﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Timers;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Crm.Sdk.Messages;
using SPP.SPServices;
using Microsoft.Win32;


public class SPSPlugin : IPlugin
{
    /// <summary>
    /// Plug-in that calls a webservice to create a Opportunity document set in SharePoint for the related entity
    /// </summary>

    public void Execute(IServiceProvider serviceProvider)
    {
        // Get execution context
        IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

        try
        {
            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                // Get entity from Input Parameters
                Entity entity = (Entity)context.InputParameters["Target"];

                if (entity.LogicalName.Equals("opportunity"))
                {
                    Entity opp = service.Retrieve("opportunity", entity.Id, new ColumnSet("stageid", "name", "parentaccountid", "parentcontactid", "estimatedvalue"));

                    if (opp.Contains("stageid"))
                    {
                        Entity stage = service.Retrieve("processstage", (Guid)opp["stageid"], new ColumnSet("stagename"));

                        if (stage["stagename"].ToString().ToUpper() == "PROPOSE")
                        {
                            Dictionary<string, string> attributes = new Dictionary<string, string>();
                            Entity parentAccount = null;
                            Entity parentContact = null;
                            Entity currentUser = service.Retrieve("systemuser", context.InitiatingUserId, new ColumnSet("domainname"));
                            string username = currentUser["domainname"].ToString();
                            string tenant = Regex.Match(username, @"\@([^.]*)\.").Groups[1].Value;
                            string site = "https://" + tenant + ".sharepoint.com/sites/Contoso/Sales/Resellers/";
                            string title = string.Empty;

                            // Set value for CustomerName key and CustomerAddress key in attributes dictionary<string, string>
                            if (opp.Contains("parentaccountid"))
                            {
                                // Retrieve parent account record
                                EntityReference parentAccountLookup = (EntityReference)opp["parentaccountid"];
                                parentAccount = service.Retrieve("account", parentAccountLookup.Id, new ColumnSet("name", "address1_composite"));
                                attributes.Add("CustomerName", parentAccount["name"].ToString());
                                attributes.Add("CustomerAddress", parentAccount["address1_composite"].ToString());
                            }

                            // Set value for CustomerContact key in attributes dictionary<string, string>
                            if (opp.Contains("parentcontactid"))
                            {
                                // Retrieve associated contact record
                                EntityReference parentContactLookup = (EntityReference)opp["parentcontactid"];
                                parentContact = service.Retrieve("contact", parentContactLookup.Id, new ColumnSet("fullname"));

                                attributes.Add("CustomerContact", parentContact["fullname"].ToString());
                            }

                            // Set title for document folder in SharePoint
                            if (parentAccount.Contains("name") && parentContact.Contains("fullname"))
                            {
                                string accountName = parentAccount["name"].ToString();

                                if (accountName.IndexOf("&") != -1)
                                {
                                    string front = accountName.Substring(0, accountName.IndexOf("&"));
                                    string end = accountName.Substring(accountName.IndexOf("&") + 1, (accountName.Length - (accountName.IndexOf("&") + 1)));

                                    accountName = front + "and" + end;
                                }

                                title = accountName + "_" + parentContact["fullname"].ToString();
                            }
                            else
                            {
                                return;
                            }

                            // Set value for Products key in attributes dictionary<string, string>
                            // Retrieve opportunity products associated with the opportunity
                            QueryExpression oppProductsQuery = new QueryExpression("opportunityproduct");
                            oppProductsQuery.Criteria.AddCondition("opportunityid", ConditionOperator.Equal, opp.Id);
                            EntityCollection relatedOppProducts = service.RetrieveMultiple(oppProductsQuery);

                            string products = " ";

                            if (relatedOppProducts.Entities.Count > 0)
                            {
                                foreach (Entity product in relatedOppProducts.Entities)
                                {
                                    // Get product name for reach related opportunity product
                                    Guid oppProdId = (Guid)product["opportunityproductid"];
                                    QueryExpression oppProdIdQuery = new QueryExpression("opportunityproductid");
                                    Entity oppProd = service.Retrieve("opportunityproduct", oppProdId, new ColumnSet("productid"));
                                    EntityReference productRef = (EntityReference)oppProd["productid"];
                                    string productName = productRef.Name.ToString();

                                    if (products == " ")
                                    {
                                        products = productName;
                                    }
                                    else if (products.Length > 0)
                                    {
                                        products = products + ", " + productName;
                                    }
                                }
                            }

                            attributes.Add("Products", products);

                            // Set value for EstimatedCost key in attributes dictionary<string, string>
                            if (opp.Contains("estimatedvalue"))
                            {
                                Money estRevValue = (Money)opp["estimatedvalue"];
                                string estRev = estRevValue.Value.ToString("C");
                                attributes.Add("EstimatedCost", estRev);
                            }

                            // Convert dictionary to array
                            ArrayOfKeyValueOfstringstringKeyValueOfstringstring[] data = attributes.Select(pair => new ArrayOfKeyValueOfstringstringKeyValueOfstringstring() { Key = pair.Key, Value = pair.Value }).ToArray();

                            // Instantiate client and properties
                            SharePointDocumentSet client = new SharePointDocumentSet();
                            DocumentSetSaveProperties properties = new DocumentSetSaveProperties()
                            {
                                SitePath = "/sites/Contoso/Sales/Resellers",
                                ListName = "Opportunities",
                                DocumentSetContentTypeName = "Sales Opportunity Set",
                                DocumentSetItemTitle = title,
                                FieldNameValueCollection = data
                            };

                            client.SaveDocumentSet(properties);

                            // Check if SharePoint Site exists
                            // Retrieve SharePoint Site
                            QueryExpression defaultSPQuery = new QueryExpression("sharepointsite");
                            defaultSPQuery.Criteria.AddCondition("absoluteurl", ConditionOperator.Equal, site);
                            EntityCollection spSites = service.RetrieveMultiple(defaultSPQuery);

                            // Create SharePoint Site record
                            if (spSites.Entities.Count < 1)
                            {
                                Entity spSite = new Entity("sharepointsite");
                                spSite["name"] = "Default Site";
                                spSite["absoluteurl"] = site;
                                spSite["isdefault"] = true;
                                spSite["validationstatus"] = new OptionSetValue(4);
                                spSite["validationstatuserrorcode"] = new OptionSetValue(2);
                                service.Create(spSite);
                            }

                            // Run retrieve for SharePoint site again
                            EntityCollection finalSPSites = service.RetrieveMultiple(defaultSPQuery);

                            // Confirm SharePoint site record is there
                            if (finalSPSites.Entities.Count == 1)
                            {
                                // Retrieve root Opportunities document location
                                Entity finalSPSite = finalSPSites.Entities[0];
                                QueryExpression rootDocLocQuery = new QueryExpression("sharepointdocumentlocation");
                                rootDocLocQuery.Criteria.AddCondition("relativeurl", ConditionOperator.Equal, "Opportunities");
                                EntityCollection rootDocLocs = service.RetrieveMultiple(rootDocLocQuery);

                                // Check if root Opportunities document location exists
                                if (rootDocLocs.Entities.Count == 1)
                                {
                                    // Retrieve document location for opportunity
                                    QueryExpression oppDocLocQuery = new QueryExpression("sharepointdocumentlocation");
                                    oppDocLocQuery.Criteria.AddCondition("relativeurl", ConditionOperator.Equal, title);
                                    EntityCollection oppDocLocs = service.RetrieveMultiple(oppDocLocQuery);

                                    // Create document location for opportunity
                                    if (oppDocLocs.Entities.Count < 1)
                                    {
                                        CreateDocLoc(service, opp, title, new EntityReference("sharepointdocumentlocation", rootDocLocs[0].Id));
                                    }
                                }

                                // Create root Opportunities document location
                                else if (rootDocLocs.Entities.Count < 1)
                                {
                                    CreateDocLoc(service, null, "Opportunities", new EntityReference("sharepointsite", finalSPSite.Id));
                                    EntityCollection finalRootOppDocLocs = service.RetrieveMultiple(rootDocLocQuery);

                                    // Create document location for opportunity
                                    if (finalRootOppDocLocs.Entities.Count == 1)
                                    {
                                        CreateDocLoc(service, opp, title, new EntityReference("sharepointdocumentlocation", finalRootOppDocLocs[0].Id));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private void CreateDocLoc(IOrganizationService service, Entity entity, String url, EntityReference parent)
    {
        Entity dl = new Entity("sharepointdocumentlocation");
        dl["name"] = url;
        dl["description"] = "";
        if (parent != null)
        {
            dl["parentsiteorlocation"] = parent;
            dl["relativeurl"] = url;
        }
        else
        {
            dl["absoluteurl"] = url;
        }
        if (entity != null)
        {
            dl["regardingobjectid"] = new EntityReference(entity.LogicalName, entity.Id);
        }
        service.Create(dl);
    }
}
